Skip to content

05 网络与存储

容器默认是相互隔离的——你的Agent容器访问不了Redis容器,因为它们在不同的"房间"里。另外,容器被删除后里面的数据就没了——你的对话记录、数据库文件全都会消失。

这两个问题分别由Docker网络和Docker存储来解决。

一、端口映射

容器有自己独立的网络命名空间,默认和外部隔离。要从宿主机访问容器内的服务,需要做端口映射。

1.1 基本用法

bash
# 宿主机8080端口 → 容器80端口
docker run -d -p 8080:80 nginx

格式是-p 宿主机端口:容器端口。访问http://localhost:8080就会被转发到容器的80端口。

1.2 EXPOSE vs 端口映射

Dockerfile里的EXPOSE只是声明,不会实际发布端口。要真正从外部访问,必须在docker run时用-p映射,或者在compose.yaml里配置ports

yaml
# compose.yaml
services:
  web:
    ports:
      - "8000:5000"

1.3 端口映射注意事项

映射端口时要注意:

  • 一个宿主机端口只能映射给一个容器
  • 不指定宿主机端口让Docker自动分配:-p 80(容器80端口映射到宿主机的随机端口)
  • 绑定到特定网卡:-p 127.0.0.1:8080:80(只允许本机访问)

安全提醒: 端口映射默认绑定到所有网卡(0.0.0.0),意味着任何能访问你机器的人都能访问这个端口。数据库这类敏感服务不要暴露端口,或者绑定到127.0.0.1

二、容器网络

2.1 默认网络

Docker安装后会创建一个默认的bridge网络。用docker run启动的容器都连接到这个网络。

bash
# 查看Docker网络列表
docker network ls

输出类似:

NETWORK ID     NAME      DRIVER    SCOPE
a1b2c3d4e5f6   bridge    bridge    local
f6e5d4c3b2a1   host      host      local
1a2b3c4d5e6f   none      null      local

三种内置网络:

网络说明
bridge默认网络,容器之间通过虚拟网桥通信
host容器直接使用宿主机的网络栈,没有隔离
none没有网络,容器完全断网

2.2 容器间通信

在同一个bridge网络里,容器可以用容器名作为主机名互相访问。

bash
# 创建自定义网络
docker network create my-network

# 启动Redis,加入my-network
docker run -d --name redis --network my-network redis:alpine

# 启动Agent服务,加入my-network
docker run -d --name agent --network my-network my-agent:1.0

在Agent容器里,可以直接用redis作为主机名连接Redis:

python
import redis
r = redis.Redis(host='redis', port=6379)

用Compose时不需要手动创建网络。 Compose会自动创建一个默认网络,所有服务都加入这个网络,服务名就是主机名。

2.3 网络别名

一个容器可以有多个网络别名:

bash
docker run -d --network my-network --network-alias db --network-alias database postgres

其他容器可以用dbdatabase访问这个容器。

三、数据持久化

容器被删除后,里面的数据就没了。如果你在容器里跑了一个Redis,存了一些数据,docker rm之后数据全部消失。

Docker提供两种数据持久化方案:Volume(数据卷)和Bind Mount(绑定挂载)。

3.1 Volume(数据卷)

Volume是Docker管理的存储区域,独立于容器的生命周期。容器删了,Volume还在。

bash
# 创建Volume
docker volume create my-data

# 启动容器并挂载Volume
docker run -d -v my-data:/data redis:alpine

-v my-data:/data的意思是把my-data这个Volume挂载到容器的/data目录。容器往/data写的数据实际存在Volume里。

验证数据持久化:

bash
# 启动Redis并写入数据
docker run -d --name redis1 -v redis-data:/data redis:alpine
docker exec redis1 redis-cli SET mykey "hello"

# 删除容器
docker rm -f redis1

# 用同一个Volume启动新容器
docker run -d --name redis2 -v redis-data:/data redis:alpine
docker exec redis2 redis-cli GET mykey
# 输出: "hello"

数据还在,因为Volume没有随容器删除。

3.2 Volume管理

bash
# 列出所有Volume
docker volume ls

# 查看Volume详情
docker volume inspect my-data

# 删除指定Volume
docker volume rm my-data

# 删除所有未使用的Volume
docker volume prune

在Compose里使用Volume:

yaml
services:
  redis:
    image: redis:alpine
    volumes:
      - redis-data:/data

# 声明Volume
volumes:
  redis-data:

docker compose down不会删除Volume,数据会保留。docker compose down -v会连Volume一起删除。

3.3 Bind Mount(绑定挂载)

Bind Mount把宿主机的目录直接挂载到容器里。和Volume不同,Bind Mount的文件直接存在宿主机上,你可以直接用编辑器修改。

bash
# 把当前目录挂载到容器的/app
docker run -d -v $(pwd):/app my-app:1.0

Bind Mount适合开发场景——你改代码,容器里立刻生效。但不适合生产环境,因为依赖宿主机的目录结构。

在Compose里使用Bind Mount:

yaml
services:
  web:
    build: .
    volumes:
      - ./src:/app/src    # 绑定挂载
      - redis-data:/data   # 命名卷

3.4 Volume vs Bind Mount

对比项VolumeBind Mount
管理方Docker管理用户管理
存储位置Docker数据目录宿主机任意目录
可移植性高(不依赖宿主机路径)低(依赖宿主机路径)
适合场景数据持久化(数据库、日志)开发时挂载代码
性能Linux上好,Mac/Windows上有性能问题

生产环境用Volume,开发环境用Bind Mount。

四、网络和存储的组合

来看一个实际的Agent服务架构:

yaml
services:
  web:
    build: .
    ports:
      - "8000:5000"
    environment:
      - REDIS_HOST=redis
    volumes:
      - app-logs:/app/logs
    depends_on:
      redis:
        condition: service_healthy

  redis:
    image: redis:alpine
    volumes:
      - redis-data:/data
    healthcheck:
      test: ["CMD", "redis-cli", "ping"]
      interval: 5s
      timeout: 3s
      retries: 5

volumes:
  redis-data:
  app-logs:

这个架构:

  • web和redis在同一个网络里,web用redis主机名访问redis
  • web的5000端口映射到宿主机的8000端口
  • redis的数据持久化到redis-data
  • web的日志持久化到app-logs
  • 健康检查保证redis就绪后再启动web

五、总结

概念作用
端口映射(-p从宿主机访问容器服务
bridge网络默认网络,容器间用服务名通信
VolumeDocker管理的数据持久化,适合生产
Bind Mount宿主机目录直接挂载,适合开发
depends_on + healthcheck控制启动顺序,保证依赖就绪

核心原则:

  1. 端口映射要谨慎——敏感服务不要暴露,或者绑定到127.0.0.1
  2. 数据要持久化——数据库、日志等数据必须用Volume,不然容器删了数据就没了
  3. 生产用Volume,开发用Bind Mount

下一篇是实战篇——把前面学到的所有知识串起来,部署一个完整的AI Agent服务。